<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
/**
* Modular Extensions - HMVC
* 
* Adapted from the CodeIgniter Core Classes
* @copyright	Copyright (c) 2006, EllisLab, Inc.
* @license		http://codeigniter.com/user_guide/license.html
* 
* Description:
* This helper provides static functions to load and instantiate controllers 
* in modules which can operate as HMVC controllers.
*  
* Modules have access to the currently loaded core classes in the same
* manner as a normal controller.
* 
* Install this file as application/helpers/modules_helper.php
* 
* Load manually or autoload as needed.
*
* @version: 4.1.05 (c) Wiredesignz 2008-05-21
**/

class Modules
{
	/** Load a module.
	 * 
	 * @return object [module]
	 * @return boolean [FALSE] module not found
	 **/	
	function &load($module, $base = 'controllers/') 
    {		
		is_array($module) ? list($module, $config) = each($module) : $config = '';
		
		list($path, $file, $home) = modules::find($module, my_router::module(), $base);
		
		if ($path === FALSE)
		{
			list($path, $file, $home) = modules::find($module, $file, $base);
		}
		
		$_module = strtolower($module);
		
		$ci =& get_instance();
		
		if (isset($ci->$_module))
		{
			return $ci->$_module;			
		}
		
		if($path === FALSE)
		{
			return $path;
		}
		
		modules::load_file($module, $path);
		
		$ci->$_module =& new $module($config);
		
		$ci->$_module->_assign_libraries($ci);
		
		return $ci->$_module;
	}

	/** Load a file
	 * 
	 * @return array [$config] or [$language] 
	 * @return boolean [TRUE] for other files
	 **/	
	function load_file($file, $path, $type = 'other', $result = TRUE)
	{ 
		$file = str_replace(EXT, '', $file);

		if ($type === 'other')
		{
			if (class_exists($file)) 
			{
				log_message('debug', "File already loaded: ".$path.$file.EXT);
				return $result;
			}
			
			include_once $path.$file.EXT;
		}
		else
		{
			include $path.$file.EXT;
			
			if ( ! isset($$type) OR ! is_array($$type))
			{		
				show_error($path.$file.EXT." does not contain a valid {$type} array");
			}
			
			$result = $$type;
		}
		
		log_message('debug', "File loaded: ".$path.$file.EXT);
		return $result;
	}
	
	/** Find a file
	 * 
	 * Scans for files located anywhere within application/modules directory.
	 * Also scans application directories for models and views.
	 * Generates fatal error on file not found.
	 * 
	 * @return array [$path, $file, $home]
	 * @return array [FALSE, $file] for some application files
	 **/	
	function find($file, $path = '', $base = 'controllers/', $subpath = '')
	{
		if (($pos = strrpos($file, '/')) !== FALSE)
	    {
			$subpath = substr($file, 0, $pos);
			
			$file = substr($file, $pos + 1);
	    }
		
		($subpath) AND $subpath .= '/';
		
		$path .= '/';
		
		$paths2scan = array(MODBASE.$path.$base.$subpath);

		/* scan application directories for controllers models and views */
		if (in_array($base, array('controllers/', 'models/', 'views/')))
		{
			$paths2scan = array_merge($paths2scan, array(MODBASE.$subpath.$base, APPPATH.$base, APPPATH.$base.$subpath));
		}
		
		/* scan system directories for language */
		if (in_array($base, array('language/')))
		{
			$paths2scan = array_merge($paths2scan, array(BASEPATH.$base.$path.$subpath));
		}
		  
		$file .= strpos($file, '.') ? '' : EXT;
		
		$fullpath = $path.$base.$file;
		
		foreach ($paths2scan as $path2)
		{			
			//echo $path2,$file,'<br/>';
			
			foreach (array($file, ucfirst($file)) as $name)
			{
				if (is_file($path2.$name))
				{
					return array($path2, str_replace(EXT, '', $name), substr($path, 0, -1));
				}
			}
		}
		
		/* file not found */
		
		/* don't die just yet, we handle these types back in the caller */
		if (in_array($base, array('config/', 'controllers/', 'helpers/', 'language/', 'libraries/', 'methods/', 'plugins/')))
		{
			return array(FALSE, str_replace(EXT, '', $file), FALSE);
		}	
		
		/* ok, die now */
		show_error("Unable to locate the requested file: ".$fullpath);
	}

	/** Run a module/method
	 * 
	 * Prevents running a protected method or 
	 * the module constructor and redirects to the
	 * module index or error method appropriately
	 * 
	 * @return mixed [module ouput]
	 **/
	function run($module, $data = '', $method = '')
    {
		if($class =& modules::load($module))
		{
			if ($method == '' OR $method == $module OR substr($method, 0, 1) == '_') $method = 'index';
			
			return (method_exists($class, $method)) ? $class->$method($data) : $class->error($method, $data);
    	}
		
		show_error("Unable to locate the requested module: ".$module);
	}
}